﻿using Core.DataAccess.Model;
using Core.Framework;
using Core.Framework.Common;
using Dapper;
using iTool.ClusterComponent;
using Local.Interface;
using Microsoft.AspNetCore.NodeServices;
using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace Silo.SocketService
{
    public class NodePackageProvider
    {
        INodeInstallPackage installPackage;

        //需要重试的包
        public static Dictionary<int, KeyValuePair<string, string>> ReInstallNodeCommandList =
            new Dictionary<int, KeyValuePair<string, string>>();


        public static readonly string[] DefaultPackages = new string[] { "axios", "crypto", "crypto-js" };

        public NodePackageProvider(INodeInstallPackage inode)
        {
            installPackage = inode;

            var job = new TimerJob();
            job.RegisterDisallowConcurrent<InstallPackageTimerJob>(DateTime.UtcNow.AddSeconds(60), action: a => a.WithIntervalInSeconds(60).RepeatForever());
        }

        public void CheckNotInstallPackage()
        {
            var packages = GetInstallPackage();

            var result = installPackage.GetNodePackageList(new Pagination
            {
                page = 1,
                rows = 9999,
                sidx = "id",
                sord = "desc"
            });

            List<NodePackage> needInstallPackages;

            if (result.Data.records > 0)
            {
                needInstallPackages = result.Data.Data as List<NodePackage>;
            }
            else
            {
                needInstallPackages = new List<NodePackage>();
            }

            if (!needInstallPackages.Any(item => item.packageName == "axios"))
            {
                needInstallPackages.Add(new NodePackage
                {
                    packageName = "axios"
                });
            }


            foreach (var item in needInstallPackages)
            {
                if (packages.Contains(item.drName))
                    continue;

                string argument = string.Empty, packageName = string.Empty;

                bool isAxiosDefaultPackage = DefaultPackages.Contains(item.packageName);
                if (isAxiosDefaultPackage)
                    continue;

                if (!string.IsNullOrWhiteSpace(item.version))
                {
                    argument = $" i {item.drName}@npm:{item.packageName}@{item.version}";
                    packageName = $"{item.drName}@npm:{item.packageName}@{item.version}";
                }
                else
                {
                    argument = $" i {item.packageName}";
                    packageName = item.packageName;
                }

                try
                {
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        var value = Executer.InsertPackge(packageName);
                        if (value.ToLower().IndexOf("error") < 0 && value.ToLower().IndexOf("failed") < 0)
                        {
                            if (!isAxiosDefaultPackage)
                            {
                                // 安装成功
                                // 更新安装包状态
                                installPackage.InstallSuccess(item.id);
                            }
                        }
                        else
                        {
                            if (!isAxiosDefaultPackage)
                            {
                                installPackage.InstallError(item.id);
                            }
                        }
                    }
                    else
                    {
                        Executer.RunAsync("npm", argument, output => (output.ToLower().IndexOf("error") < 0 && output.ToLower().IndexOf("failed") < 0),
                                                            isSuccess =>
                                                            {

                                                                if (isSuccess)
                                                                {
                                                                    if (!isAxiosDefaultPackage)
                                                                    {
                                                                        // 安装成功
                                                                        // 更新安装包状态
                                                                        installPackage.InstallSuccess(item.id);
                                                                    }
                                                                }
                                                                else
                                                                {
                                                                    // 安装失败
                                                                    // 更新状态
                                                                    // 进行重试
                                                                    ReInstallNodeCommandList.Add(item.id, new KeyValuePair<string, string>("npm", argument));
                                                                    if (!isAxiosDefaultPackage)
                                                                    {
                                                                        installPackage.InstallError(item.id);
                                                                    }
                                                                }
                                                            });
                    }




                }
                catch (Exception ex)
                {
                    Console.WriteLine("4. ExecuteInstallPackage: " + ex.Message);
                }
            }
        }

        /// <summary>
        /// 获取所有本地已安装的包
        /// </summary>
        /// <returns></returns>
        private List<string> GetInstallPackage()
        {
            // node_modules
            if (!Directory.Exists("node_modules"))
            {
                Directory.CreateDirectory("node_modules");
                return new List<string>();
            }

            DirectoryInfo dir = new DirectoryInfo("node_modules/");
            DirectoryInfo[] subDirs = dir.GetDirectories();
            return subDirs.Select(a => a.Name).ToList();
        }

    }

    /// <summary>
    /// 扫描依赖安装包
    /// </summary>
    public class InstallPackageTimerJob : ITimerJob
    {
        public void Execute(IJobExecutionContext context)
        {
            var installPackage = ProviderOfServices.GetService<INodeInstallPackage>();

            foreach (var item in NodePackageProvider.ReInstallNodeCommandList)
            {
                Executer.RunAsync(item.Value.Key, item.Value.Value, output => output.ToLower().IndexOf("error") < 0,
                        isSuccess =>
                        {
                            if (isSuccess)
                            {
                                // 安装成功
                                // 更新安装包状态
                                installPackage.InstallSuccess(item.Key);
                            }
                            else
                            {
                                // 安装失败
                                // 更新状态
                                // 进行重试
                                NodePackageProvider.ReInstallNodeCommandList.Add(item.Key, item.Value);
                                installPackage.InstallError(item.Key);
                            }
                        });
            }

        }
    }

    /// <summary>
    /// 订阅消费者
    /// </summary>
    public class iToolConsumerProvider
    {
        IDBFactory iDBFactory;
        INodeInstallPackage installPackage;
        INodeServices iNodeServices;
        ILogger<iToolConsumerProvider> logger;

        public iToolConsumerProvider(INodeInstallPackage installPackage, IDBFactory iDBFactory, INodeServices iNodeServices, ILogger<iToolConsumerProvider> logger)
        {
            this.logger = logger;
            this.iDBFactory = iDBFactory;
            this.installPackage = installPackage;
            this.iNodeServices = iNodeServices;
            this.InitScript();
        }

        public void ExecuteInstallPackage(KeyValuePair<string, string> message)
        {
            //File.AppendAllText("installpackage.txt", $"\n{DateTime.Now} ：" + message.Value);

            foreach (var package in NodePackageProvider.DefaultPackages)
            {
                bool isAxiosDefaultPackage = message.Value.IndexOf(package) > -1;
                if (isAxiosDefaultPackage)
                    return;
            }
            

            var argument = message.Value.TrimStart("npm".ToArray());

            try
            {
                var args = argument.Split(" ");

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    var value = Executer.InsertPackge(args[args.Length - 1]);
                    if (value.ToLower().IndexOf("error") < 0 && value.ToLower().IndexOf("failed") < 0)
                    {
                        installPackage.InstallSuccess(message.Key.ToInt());
                    }
                    else
                    {
                        NodePackageProvider.ReInstallNodeCommandList
                            .Add(message.Key.ToInt(), new KeyValuePair<string, string>("npm", argument));
                        installPackage.InstallError(message.Key.ToInt());
                    }
                }
                else
                {
                    Executer.RunAsync("npm", argument, output => (output.ToLower().IndexOf("error") < 0 && output.ToLower().IndexOf("failed") < 0),
                    isSuccess =>
                    {
                        if (isSuccess)
                        {
                            // 安装成功
                            // 更新安装包状态
                            installPackage.InstallSuccess(message.Key.ToInt());
                        }
                        else
                        {
                            // 安装失败
                            // 更新状态
                            // 进行重试
                            NodePackageProvider.ReInstallNodeCommandList
                        .Add(message.Key.ToInt(), new KeyValuePair<string, string>("npm", argument));
                            installPackage.InstallError(message.Key.ToInt());
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("4. ExecuteInstallPackage: " + ex.Message);
            }
        }

        public void ExecuteScriptDelete(KeyValuePair<string, string> message)
        {
            string file = message.Key.Replace("_module", "");
            // 文件名称
            var filePathOfRequire = $"{file}.js";
            var filePathOfModule = $"{file}_module.js";

            try
            {
                if (File.Exists(filePathOfRequire))
                    File.Delete(filePathOfRequire);

                if (File.Exists(filePathOfModule))
                    File.Delete(filePathOfModule);
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "ExecuteScriptDelete");
            }
        }

        /// <summary>
        /// 生成云函数文件
        /// </summary>
        /// <param name="message"></param>
        public void ExecuteScriptBudiler(KeyValuePair<string, string> message)
        {
            // 声明文件名称
            var filePathOfRequire = $"{message.Key}.js";
            var filePathOfModule = $"{message.Key}_module.js";

            // 模块名称
            var moduleName = message.Key.Replace("./CloudFunctions/", "");

            // 原文信息
            string scriptContent = message.Value;

            // 函数格式化
            if (!new string[] { "AppSetting", "Global" }.Contains(moduleName))
            {
                var task = this.iNodeServices.InvokeAsync<string>("./FunctionFormatTemplate", message.Value);
                scriptContent = task.Result;
            }

            try
            {
                DirectoryInfo info = new DirectoryInfo(filePathOfRequire);

                // 文件夹是否存在
                if (!Directory.Exists(info.Parent.FullName))
                    Directory.CreateDirectory(info.Parent.FullName);

                // 写入源文件
                File.WriteAllText(filePathOfRequire, message.Value);
                // 写入格式化后的文件
                File.WriteAllText(filePathOfModule, scriptContent);

                if ("AppSetting" == moduleName)
                {
                    var task = this.iNodeServices.InvokeAsync<string>("./GetAppSetting");
                    File.WriteAllText("appsettings.json", task.Result);
                }

            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "ExecuteScriptBudiler");
            }

        }

        private void InitScript()
        {
            Print.Line("\niTool> Init builder script...", ConsoleColor.DarkYellow);

            using (var db = this.iDBFactory.Create(DatabaseType.Function))
            {
                var funcs = db.Query<Function>("SELECT [modulePath],[scriptContent] FROM [Function]");

                if (funcs?.Count() > 0)
                {
                    foreach (var item in funcs)
                    {
                        try
                        {
                            this.ExecuteScriptBudiler(new KeyValuePair<string, string>(item.modulePath, item.scriptContent));
                        }
                        catch (Exception ex)
                        {
                            _ = ex;
                        }
                    }
                }
            }

            Print.Line("iTool> Init Builder Script success.", ConsoleColor.Green);

        }

    }

}
